﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace YinLongTool.Net
{
    /// <summary>
    /// WinHttpRequest
    /// </summary>
    public class WinHttpR
    {
        #region 私有成员

        private Type winhttpObj;
        private object ComInstance;

        /// <summary>
        /// 执行的函数
        /// </summary>
        /// <param name="MethodName"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public object DoMethod(string MethodName, object[] args)
        {
            return winhttpObj.InvokeMember(MethodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Static, null, ComInstance,
                args);
        }

        /// <summary>
        /// 执行的函数
        /// </summary>
        /// <param name="MethodName"></param>
        /// <param name="args"></param>
        /// <param name="ParamMods"></param>
        /// <returns></returns>
        public object DoMethod(string MethodName, object[] args, System.Reflection.ParameterModifier[] ParamMods)
        {
            return winhttpObj.InvokeMember(MethodName, System.Reflection.BindingFlags.InvokeMethod, null, ComInstance,
                args, ParamMods, null, null);
        }

        /// <summary>
        /// 获得属性与设置属性
        /// </summary>
        /// <param name="propName"></param>
        public object this[string propName]
        {
            get
            {
                return winhttpObj.InvokeMember(propName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.GetProperty, null, ComInstance,
                    null);
            }
            set
            {
                winhttpObj.InvokeMember(propName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.SetProperty, null, ComInstance,
                    new object[] { value });
            }
        }

        /// <summary>
        /// 本次访问的Url （存储用于302解析）
        /// </summary>
        private string UrlA;

        /// <summary>
        /// 是否为POST访问
        /// </summary>
        private bool IsPOST;

        /// <summary>
        /// 本次是否为异步访问
        /// </summary>
        private bool IsAsync;

        /// <summary>
        /// 自动模式
        /// </summary>
        private bool _Auto;

        private bool _IsUserAgent;
        private bool _IsContentType;
        private bool _IsAcceptLanguage;

        /// <summary>
        /// Cookies自动模式
        /// </summary>
        private int _AutoCookies;

        /// <summary>
        /// 模式1内部Cookies
        /// </summary>
        private string _Cookies;

        private int _Cookieslen;

        /// <summary>
        /// 是否允许自动重定向
        /// </summary>
        private bool Redirect;

        /// <summary>
        /// 自动递归重定向计次 默认一次访问最多10次重定向
        /// </summary>
        private int _RedirectIndex;

        #endregion


        /// <summary>
        /// 初始化
        /// </summary>
        public WinHttpR()
        {
            __Create();
            __InitOptions();
        }

        private void __Create()
        {

            //创建 WinHttp对象
            winhttpObj = Type.GetTypeFromProgID("WinHttp.WinHttpRequest.5.1");
            if (this.winhttpObj == null)
                throw new Exception("指定的COM对象名称无效");
            ComInstance = System.Activator.CreateInstance(this.winhttpObj);
        }

        private void __Close()
        {
        }

        /// <summary>
        /// 初始化一些默认配置选项
        /// </summary>
        private void __InitOptions()
        {
            _Auto = true;
            _AutoCookies = 0;
            Redirect = true;
            DoMethod("Option", new object[] { 4, 13056 }); //自动忽略错误/证书错误
            //winhttpObj["Option"] = new object[] {4, 13056}; //自动忽略错误/证书错误
            _Cookies = " ;";
            _Cookieslen = 2;
        }

        /// <summary>
        /// 加载并设置内部Cookies 1
        /// </summary>
        private void __LoadCookies1()
        {
            DoMethod("SetRequestHeader", new object[] { "Cookie", _Cookies.Substring(2, _Cookieslen - 4) });
        }

        /// <summary>
        /// 加载并设置本地IESCookies 2
        /// </summary>
        private void __LoadCookies2()
        {
        }

        /// <summary>
        /// Send前自动处理补全必须协议头
        /// </summary>
        /// <param name="IsData">是否有提交数据</param>
        private void __SetRequestHeaders(bool IsData)
        {
            if (_IsUserAgent == false)
            {
                DoMethod("SetRequestHeader",
                    new object[] { "User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2)" });
            }

            if (_IsAcceptLanguage == false)
            {
                DoMethod("SetRequestHeader",
                    new object[] { "Accept-Language", "zh-cn" });
            }

            if (_IsContentType == false)
            {
                if (IsPOST == true || IsData == true)
                {
                    DoMethod("SetRequestHeader",
                        new object[] { "Content-Type", "application/x-www-form-urlencoded" });
                }
            }
        }

        /// <summary>
        /// Send前处理
        /// </summary>
        private void __SetInternetInfo()
        {
            if (_AutoCookies > 0)
            {
                if (_AutoCookies == 1)
                {
                    __LoadCookies1();
                }
                else if (_AutoCookies == 2)
                {
                    __LoadCookies2();
                }
            }
        }
        /// <summary>
        /// Send处理
        /// </summary>
        /// <param name="NopNullCookieName">默认=假 自动更新Cookies时忽略掉Cookie键值为空的Cookie （必须在'非AutoCookies模式0'下使用）</param>
        public void __GetQueryHeadersInfo(bool NopNullCookieName=false)
        {
            if (IsAsync==true)
            {
                return;
            }
            //处理并更新cookie
            if (_AutoCookies>0)
            {
                if (_AutoCookies==1)
                {
                    
                }else if (_AutoCookies==2)
                {

                }

                if (Redirect)
                {
                    __Redirect();
                }
            }
        }
        /// <summary>
        /// AutoCookie自动递归处理重定向
        /// </summary>
        /// <param name="NopNullCookieName">默认=假 自动更新Cookies时忽略掉Cookie键值为空的Cookie （必须在'非AutoCookies模式0'下使用）</param>
        private void __Redirect(bool NopNullCookieName=false)
        {

        }
        /// <summary>
        /// 设置自动补全模式 此模式开启后会自动帮你补全必要的协议头（目前只包括Content-Type,Accept,Accept-Language,Cache-Control） （设置后一直有效） （必须在Open前使用）
        /// </summary>
        /// <param name="IsAuto">留空为真 真=开启自动协议头补全 假=关闭自动协议头补全</param>
        public void Auto(bool? IsAuto)
        {
            if (!IsAuto.HasValue)
            {
                IsAuto = true;
            }

            _Auto = IsAuto.Value;
        }

        /// <summary>
        /// 设置Cookies自动管理模式 （设置后一直有效） （必须在Open前使用）
        /// </summary>
        /// <param name="Index">留空=1 0=Winhttp内部自动处理Cookies(完全和Winhttpr5.1一样的特性)  1=类内部自动合并更新Cookies(此模式下可以配合独有方法Cookies CookieAdd CookieSet CookieDel 来取/设/添加/设置/删除)  2=缓存到本地(支持IES控件继承 注意:模式2不兼容多线程)</param>
        public void AutoCookies(int? Index)
        {
            if (!Index.HasValue)
            {
                Index = 1;
            }

            if (Index > 2 || Index < 0)
            {
                _AutoCookies = 0;
            }
            else
            {
                _AutoCookies = Index.Value;
            }

            if (_AutoCookies == 0)
            {
                if (Redirect) // 恢复重定向选项 允许
                {
                    DoMethod("Option", new object[] { 6, 1 }); //自动忽略错误/证书错误
                   
                }
            }
            else
            {
                DoMethod("Option", new object[] { 6, 0 }); //为其他模式 设置重定向为 禁止
            }
        }

        /// <summary>
        /// 重置(初始化)WinHttp 释放所有数据 包括之前所有设置和Cookies
        /// </summary>
        public void Rest()
        {
            __Close();
            __Create();
            __InitOptions();
        }

        /// <summary>
        /// 打开一个HTTP连接
        /// </summary>
        /// <param name="Method">例：POST、GET、HEAD 默认为:GET。</param>
        /// <param name="Url">例：http://www.nixsw.com/。</param>
        /// <param name="Async">是否异步 默认为:假=同步模式 （注意：如果为异步 则不支持AutoCookies模式1和模式2 只能用模式0）</param>
        public void Open(string? Method, string Url, bool? Async)
        {
            if (!Async.HasValue)
            {
                Async = false;
                IsAsync = Async.Value;
            }

            if (string.IsNullOrEmpty(Method))
            {
                Method = "GET";
            }

            if (_Auto)
            {
                IsPOST = Method == "POST";
                _IsUserAgent = _IsAcceptLanguage = _IsContentType = false;
            }

            UrlA = Url;
            if (UrlA.Length < 8)
            {
                UrlA = "http://" + UrlA;
            }
            else
            {
                string str = UrlA.Substring(0, 8);
                str = str.ToLower();
                if (str != "https://" && str.Substring(0, 7) != "http://")
                {
                    UrlA = "http://" + UrlA;
                }
            }

            DoMethod("Open", new object[] { Method, UrlA, IsAsync });
        }

        public void SenBin(byte[] Data, bool NopNullCookieName)
        {
        }

        public void Send()
        {
            __SetInternetInfo();

        }
        /// <summary>
        /// 快速设置Content-Type信息 （必须在Open后使用）
        /// </summary>
        /// <param name="ContentTypeValue">留空为：application/x-www-form-urlencoded </param>
        public void SetContentType(string? ContentTypeValue)
        {
            if (string.IsNullOrEmpty(ContentTypeValue))
            {
                ContentTypeValue = "application/x-www-form-urlencoded";
            }
            if (_Auto)
            {
                _IsContentType = true;
            }
            DoMethod("SetRequestHeader", new object[] { "Content-Type", ContentTypeValue });
        }
        /// <summary>
        /// 快速设置x-requested-with 为 XMLHttpRequest （必须在Open后使用）
        /// </summary>
        public void SetXMLHttpRequest()
        {
            DoMethod("SetRequestHeader", new object[] { "x-requested-with", "XMLHttpRequest" });
        }
        /// <summary>
        /// 快速设置多重伪造IP协议头（包括：X-Forwarded-For,CLIENT_IP,VIA,REMOTE_ADDR） （必须在Open后使用）
        /// </summary>
        /// <param name="FakeIP">要告知服务器的伪造IP地址。例如：123.123.123.123 </param>
        public void SetFakeIP(string FakeIP)
        {
            DoMethod("SetRequestHeader", new object[] { "X-Forwarded-For", FakeIP });
            DoMethod("SetRequestHeader", new object[] { "CLIENT_IP", FakeIP });
            DoMethod("SetRequestHeader", new object[] { "VIA", FakeIP });
            DoMethod("SetRequestHeader", new object[] { "REMOTE_ADDR", FakeIP });
        }
        /// <summary>
        /// 取/设内部Cookies （必须在AutoCookies模式1下使用）
        /// </summary>
        /// <param name="NewCookies">留空为取 空文本为清除 有数据为赋值</param>
        /// <returns></returns>
        public string Cookies(string NewCookies)
        {
            if (_AutoCookies != 1)
            {
                return "";
            }

            if (string.IsNullOrEmpty(NewCookies))
            {
                return _Cookies.Substring(2, _Cookieslen - 4);
            }

            string str = string.Empty;
            if (NewCookies.Substring(0, 2) != "; ")
            {
                str = "; " + NewCookies;
            }
            else
            {
                str = NewCookies;
            }

            if (str.Substring(str.Length - 1 - 2, 2) != "; ")
            {
                string text = str.Substring(str.Length - 1 - 1, 1);
                if (text != ";")
                {
                    str = str + ";";
                }

                if (text != " ")
                {
                    str = str + " ";
                }
            }

            _Cookies = str;
            _Cookieslen = _Cookies.Length;
            return NewCookies;
        }
        /// <summary>
        /// 获取内部Cookies中的某个Cookie （必须在AutoCookies模式1下使用）
        /// </summary>
        /// <param name="Name">Cookie名称</param>
        /// <param name="withName">是否把Cookie名称附带上返回</param>
        /// <returns></returns>
        public string CookieGet(string Name, bool withName = false)
        {
            string str = string.Empty;
            if (_AutoCookies != 1 || string.IsNullOrEmpty(Name))
            {
                return "";
            }
            int i = _Cookies.IndexOf("; " + Name, StringComparison.Ordinal);
            if (i != -1)
            {
                i = i + 2;
                int len = Name.Length;
                int ii = _Cookies.IndexOf(";", i + len, StringComparison.Ordinal);
                if (ii != -1)
                {
                    if (withName == false)
                    {
                        i = i + len;
                    }

                    str = _Cookies.Substring(i, ii - i);
                }
            }
            return str;
        }
        /// <summary>
        /// 添加或替换Cookie到内部Cookies （必须在AutoCookies模式1下使用）
        /// </summary>
        /// <param name="Cookie">单个或多个Cookie （例如：abc=123 或是 abc=123; def=456;g=nima）</param>
        /// <returns></returns>
        public bool CookieAdd(string Cookie)
        {
            bool boo = false;
            if (_AutoCookies != 1 || Cookie == "")
            {
                return false;
            }
            string[] strs = Cookie.Split(new char[] { ';' });
            for (int n = 0; n < strs.Length; n++)
            {
                strs[n] = strs[n].Trim();
                int i = strs[n].IndexOf("=", StringComparison.Ordinal);
                if (i != -1)
                {
                    string name = "; " + strs[n].Substring(0, i) + "=";
                    i = _Cookies.IndexOf(name, StringComparison.Ordinal);//Cookie名区分大小写
                    if (i != -1)
                    {
                        int ii = _Cookies.IndexOf("; ", i + name.Length, StringComparison.Ordinal);
                        if (ii != -1)
                        {
                            i = i + 2;
                            _Cookies = _Cookies.Remove(i, ii - i);
                            _Cookies = _Cookies.Insert(i, strs[n]);
                            boo = true;
                        }
                    }
                    else
                    {
                        _Cookies = _Cookies + strs[n] + "; ";
                        boo = true;
                    }
                }
            }

            if (boo)
            {
                _Cookieslen = _Cookies.Length;
            }
            return boo;
        }
        /// <summary>
        /// 删除内部Cookies中的Cookie （必须在AutoCookies模式1下使用）
        /// </summary>
        /// <param name="Cookie">单个或多个Cookie或Cookie名称 （例如：abc 或是 abc=123 或是 或是 abc; def;g 或是 abc=123; def=456;g=nima;id）</param>
        /// <returns></returns>
        public bool CookieDel(string Cookie)
        {
            bool boo = false;
            if (_AutoCookies != 1 || string.IsNullOrEmpty(Cookie))
            {
                return boo;
            }

            string[] strs = Cookie.Split(new char[] { ';' });
            for (int n = 0; n < strs.Length; n++)
            {
                strs[n] = strs[n].Trim();
                int i = strs[n].IndexOf("=", StringComparison.Ordinal);
                if (i != -1)
                {
                    strs[n] = strs[n].Substring(0, i);
                }
                strs[n] = "; " + strs[n] + "=";
                i = _Cookies.IndexOf(strs[n], StringComparison.Ordinal);
                if (i != -1)
                {
                    int ii = _Cookies.IndexOf("; ", i + strs[n].Length, StringComparison.Ordinal);
                    if (ii != -1)
                    {
                        _Cookies = _Cookies.Remove(i, ii - i);
                        boo = true;
                    }
                }
            }
            if (boo == true)
            {
                _Cookieslen = _Cookies.Length;
            }
            return boo;
        }
    }











}